﻿namespace Jsl.FxCop
{
    using System;
    using System.CodeDom.Compiler;
    using System.IO;
    using System.Text;
    using Microsoft.VisualStudio.CodeAnalysis.Extensibility;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class TestUseCharInsteadOfString
    {
        #region String.IndexOf and LastIndexOf
        [TestMethod]
        public void Should_replace_string_with_char_in_IndexOf()
        {
            ListBuilder<Action>
                .AddItem(() => "xxx".IndexOf("x"))
                .AddItem(() => "xxx".IndexOf("x", 1))
                .AddItem(() => "xxx".IndexOf("x", 1, 2))
                .AddItem(() => "xxx".LastIndexOf("x"))
                .AddItem(() => "xxx".LastIndexOf("x", 1))
                .AddItem(() => "xxx".LastIndexOf("x", 1, 2))
                .Run(method =>
                    {
                        new UseCharInsteadOfString()
                            .RunMethodRule(method)
                            .HasProblem(
                                100,
                                FixCategories.NonBreaking,
                                MessageLevel.Warning,
                                "Replace \"x\" string constant with a 'x' character constant.")
                            .HasNoMoreProblems();
                    });
               
        }

        [TestMethod]
        public void Can_not_use_char_if_more_than_one_character_in_string_in_IndexOf()
        {
            ListBuilder<Action>
                .AddItem(() => "xxx".IndexOf("xx"))
                .AddItem(() => "xxx".IndexOf("xx", 1))
                .AddItem(() => "xxx".IndexOf("xx", 1, 2))
                .AddItem(() => "xxx".LastIndexOf("xx"))
                .AddItem(() => "xxx".LastIndexOf("xx", 1))
                .AddItem(() => "xxx".LastIndexOf("xx", 1, 2))
                .Run(method =>
                    {
                        new UseCharInsteadOfString()
                            .RunMethodRule(method)
                            .HasNoMoreProblems();
                    });
        }

        [TestMethod]
        public void Ignore_overloads_of_IndexOf_that_do_not_take_char()
        {
            ListBuilder<Action>
                .AddItem(() => "xxx".IndexOf("x", StringComparison.Ordinal))
                .AddItem(() => "xxx".IndexOf("x", 1, StringComparison.Ordinal))
                .AddItem(() => "xxx".IndexOf("x", 1, 2, StringComparison.Ordinal))
                .AddItem(() => "xxx".LastIndexOf("x", StringComparison.Ordinal))
                .AddItem(() => "xxx".LastIndexOf("x", 1, StringComparison.Ordinal))
                .AddItem(() => "xxx".LastIndexOf("x", 1, 2, StringComparison.Ordinal))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasNoMoreProblems();
                });
        }
        #endregion String.IndexOf and LastIndexOf

        #region String.Replace
        [TestMethod]
        public void Should_replace_two_single_character_strings_with_chars_in_Replace()
        {
            new UseCharInsteadOfString()
                .RunMethodRule(() => "xxx".Replace("x", "z"))
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Replace \"x\" and \"z\" string constants with 'x' and 'z' character constants.")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Ignore_overloads_of_Replace_that_do_not_take_two_strings()
        {
            new UseCharInsteadOfString()
                .RunMethodRule(() => "xxx".Replace('x', 'z'))
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Ignore_multiple_character_stings_in_Replace()
        {
            ListBuilder<Action>
                .AddItem(() => "xxx".Replace("xx", "z"))
                .AddItem(() => "xxx".Replace("x", "zz"))
                .AddItem(() => "xxx".Replace("xx", "zz"))
                .AddItem(() => "xxx".Replace("", "z"))
                .AddItem(() => "xxx".Replace("x", ""))
                .Run(method =>
                    {
                        new UseCharInsteadOfString()
                            .RunMethodRule(method)
                            .HasNoMoreProblems();
                    });
        }
        #endregion String.Replace

        #region StringBuilder.Append
        [TestMethod]
        public void StringBuilder_Append_with_single_character_string_can_be_optimized()
        {
            new UseCharInsteadOfString()
                .RunMethodRule(() => ((StringBuilder)null).Append("x"))
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Replace \"x\" string constant with a 'x' character constant.")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void StringBuilder_Append_with_multiple_repeated_character_string_can_be_optimized()
        {
            new UseCharInsteadOfString()
                .RunMethodRule(() => ((StringBuilder)null).Append("xxxx"))
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Replace StringBuilder.Append(\"xxxx\") with StringBuilder.Append('x', 4).")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void StringBuilder_Append_can_not_optimize()
        {
            ListBuilder<Action>
                .AddItem(() => ((StringBuilder)null).Append(true))
                .AddItem(() => ((StringBuilder)null).Append('x'))
                .AddItem(() => ((StringBuilder)null).Append("Bob"))
                .Run(method =>
                    {
                        new UseCharInsteadOfString()
                            .RunMethodRule(method)
                            .HasNoMoreProblems();
                    });
        }
        #endregion StringBuilder.Append

        #region StringBuilder.Insert
        [TestMethod]
        public void StringBuilder_Insert_with_single_character_string_can_be_optimized()
        {
            new UseCharInsteadOfString()
                .RunMethodRule(() => ((StringBuilder)null).Insert(0, "x"))
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Replace \"x\" string constant with a 'x' character constant.")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void StringBuilder_Insert_can_not_optimize()
        {
            ListBuilder<Action>
                .AddItem(() => ((StringBuilder)null).Insert(0, true))
                .AddItem(() => ((StringBuilder)null).Insert(0, 'x'))
                .AddItem(() => ((StringBuilder)null).Insert(0, "Bob"))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasNoMoreProblems();
                });
        }
        #endregion StringBuilder.Insert

        #region StringBuilder.Replace
        [TestMethod]
        public void Should_replace_two_single_character_strings_with_chars_in_StringBuilder_Replace()
        {
            ListBuilder<Action>
                .AddItem(() => ((StringBuilder)null).Replace("x", "z"))
                .AddItem(() => ((StringBuilder)null).Replace("x", "z", 0, 0))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasProblem(
                            100,
                            FixCategories.NonBreaking,
                            MessageLevel.Warning,
                            "Replace \"x\" and \"z\" string constants with 'x' and 'z' character constants.")
                        .HasNoMoreProblems();
                });
        }

        [TestMethod]
        public void Ignore_overloads_of_StringBuilder_Replace_that_do_not_take_two_strings()
        {
            ListBuilder<Action>
                .AddItem(() => ((StringBuilder)null).Replace('x', 'z'))
                .AddItem(() => ((StringBuilder)null).Replace('x', 'z', 0, 0))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasNoMoreProblems();
                });
        }

        [TestMethod]
        public void Ignore_multiple_character_stings_in_StringBuilder_Replace()
        {
            ListBuilder<Action>
                .AddItem(() => ((StringBuilder)null).Replace("xx", "z"))
                .AddItem(() => ((StringBuilder)null).Replace("x", "zz"))
                .AddItem(() => ((StringBuilder)null).Replace("xx", "zz"))
                .AddItem(() => ((StringBuilder)null).Replace("", "z"))
                .AddItem(() => ((StringBuilder)null).Replace("x", ""))
                .AddItem(() => ((StringBuilder)null).Replace("xx", "z", 0, 0))
                .AddItem(() => ((StringBuilder)null).Replace("x", "zz", 0, 0))
                .AddItem(() => ((StringBuilder)null).Replace("xx", "zz", 0, 0))
                .AddItem(() => ((StringBuilder)null).Replace("", "z", 0, 0))
                .AddItem(() => ((StringBuilder)null).Replace("x", "", 0, 0))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasNoMoreProblems();
                });
        }
        #endregion StringBuilder.Replace

        #region Write and WriteLine
        [TestMethod]
        public void Write_with_single_character_string_can_be_optimized()
        {
            ListBuilder<Action>
                .AddItem(() => Console.Write("x"))
                .AddItem(() => ((BinaryWriter)null).Write("x"))
                .AddItem(() => ((TextWriter)null).Write("x"))
                .AddItem(() => ((StreamWriter)null).Write("x"))
                .AddItem(() => ((StringWriter)null).Write("x"))
                .AddItem(() => ((IndentedTextWriter)null).Write("x"))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasProblem(
                            100,
                            FixCategories.NonBreaking,
                            MessageLevel.Warning,
                            "Replace \"x\" string constant with a 'x' character constant.")
                        .HasNoMoreProblems();
                });
        }

        [TestMethod]
        public void WriteLine_with_single_character_string_can_be_optimized()
        {
            ListBuilder<Action>
                .AddItem(() => Console.WriteLine("x"))
                .AddItem(() => ((TextWriter)null).WriteLine("x"))
                .AddItem(() => ((IndentedTextWriter)null).WriteLine("x"))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasProblem(
                            100,
                            FixCategories.NonBreaking,
                            MessageLevel.Warning,
                            "Replace \"x\" string constant with a 'x' character constant.")
                        .HasNoMoreProblems();
                });
        }

        [TestMethod]
        public void Write_can_not_optimize()
        {
            ListBuilder<Action>
                .AddItem(() => Console.Write("bob"))
                .AddItem(() => ((BinaryWriter)null).Write("bob"))
                .AddItem(() => ((TextWriter)null).Write("bob"))
                .AddItem(() => ((StreamWriter)null).Write("bob"))
                .AddItem(() => ((StringWriter)null).Write("bob"))
                .AddItem(() => ((IndentedTextWriter)null).Write("bob"))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasNoMoreProblems();
                });
        }

        [TestMethod]
        public void WriteLine_can_not_optimize()
        {
            ListBuilder<Action>
                .AddItem(() => Console.WriteLine("bob"))
                .AddItem(() => ((TextWriter)null).WriteLine("bob"))
                .AddItem(() => ((IndentedTextWriter)null).Write("bob"))
                .Run(method =>
                {
                    new UseCharInsteadOfString()
                        .RunMethodRule(method)
                        .HasNoMoreProblems();
                });
        }
        #endregion Console.Write and WriteLine
    }
}